package com.hmall.order.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.clients.ItemClient;
import com.hmall.common.clients.UserClient;
import com.hmall.common.constants.OrderStatusConstants;
import com.hmall.common.dto.Address;
import com.hmall.common.dto.Item;
import com.hmall.common.response.ItemUpdateStockVO;
import com.hmall.order.context.BaseContext;
import com.hmall.order.mapper.OrderDetailMapper;
import com.hmall.order.mapper.OrderLogisticsMapper;
import com.hmall.order.mapper.OrderMapper;
import com.hmall.order.pojo.Order;
import com.hmall.order.pojo.OrderDetail;
import com.hmall.order.pojo.OrderLogistics;
import com.hmall.order.service.IOrderService;
import com.hmall.order.web.request.OrderCreateDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.UUID;

@Service
@Slf4j
public class OrderService extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderDetailMapper orderDetailMapper;
    @Resource
    private OrderLogisticsMapper orderLogisticsMapper;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private ItemClient itemClient;
    @Resource
    private UserClient userClient;
    /**
     * 创建订单
     *
     * @param orderCreateDTO 购买数量、付款方式、收货人地址id、商品id
     * @return 订单id
     */
    @Override
    @Transactional
    public Long createOrder(OrderCreateDTO orderCreateDTO) {

        Long itemId = orderCreateDTO.getItemId();//商品id
        Integer num = orderCreateDTO.getNum();//购买数量
        // 1- 根据itemId查询商品信息
        Item item = itemClient.findByItemId(itemId);
        // 2- 封装Order对象，将Order写入数据库tb_order表中
        Order order = new Order();
        // 2.1- 设置订单状态为未支付
        order.setStatus(OrderStatusConstants.UN_PAID);
        // 2.2- 设置订单总价格
        Long totalFee = item.getPrice() * num;
        order.setTotalFee(totalFee);
        // 2.3- 设置付款方式
        order.setPaymentType(orderCreateDTO.getPaymentType());
        //2.4- 设置用户id
        order.setUserId(Long.valueOf(BaseContext.getCurrentId()));
        // 2.5 设置订单时间
        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        long orderId = IdWorker.getId();
        order.setId(orderId);
        orderMapper.insert(order);
        // 4-将商品信息、orderId信息封装为OrderDetail对象，写入tb_order_detail表
        OrderDetail orderDetail = new OrderDetail();
        // 4.1- 设置订单id
        orderDetail.setOrderId(orderId);
        // 4.2- 设置商品id
        orderDetail.setItemId(itemId);
        // 4.3- 设置商品购买数量
        orderDetail.setNum(num);
        // 4.4- 设置商品相关信息(商品)
        BeanUtils.copyProperties(item,orderDetail);
        orderDetailMapper.insert(orderDetail);
        // 5- 根据addressId查询user-service服务，获取地址信息
        Address address = userClient.findByAddressId(orderCreateDTO.getAddressId());
        // 6- 将地址信息封装为OrderLogistics对象，写入tb_order_logistics表
        OrderLogistics orderLogistics = new OrderLogistics();
        // 6.1- 设置订单id
        orderLogistics.setOrderId(orderId);
        // 6.2- 将地址相关信息封装进目标对象
        BeanUtils.copyProperties(address,orderLogistics);
        // 6.3- 设置时间相关
        orderLogistics.setCreateTime(new Date());
        orderLogistics.setUpdateTime(new Date());
        orderLogisticsMapper.insert(orderLogistics);
        // 7- 调用item-service的减库存接口(下单就扣库存)
        ItemUpdateStockVO result = itemClient.updateStock(itemId, num);
        log.info("更新结果：{}",result);
        // 8- 发送延迟消息
        sendDelayMsg(orderId);
        return orderId;
    }

    /**
     * 发送延迟消息
     * @param orderId
     */
    private void sendDelayMsg(Long orderId) {
        Message message = MessageBuilder
                .withBody(orderId.toString().getBytes(StandardCharsets.UTF_8))
                .setHeader("x-delay",5000)
                .build();
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend("delay.direct", "delay", message, correlationData);
        log.debug("发送消息成功");
    }
}
